use std::fs;
use serde_json::{Value, Map};
use std::path::PathBuf;
use dirs_next::config_dir;
use serde_json::json;
use reqwest::Client;
use netstat2::{get_sockets_info, AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo};
use reqwest::blocking::get;
use flate2::read::GzDecoder;
use tar::Archive;


use std::process::{Command, Child};
use std::sync::Mutex;
use tauri::command;
use lazy_static::lazy_static;

use crate::controller::response::ApiResponse;

/// 下载 frpc tar.gz 并解压到 <config_dir>/frp-tauri
/// 返回解压后的目录路径
#[command]pub async fn download_and_extract_frpc() -> ApiResponse<String> {
    use std::fs;
    use std::path::Path;

    // 获取平台信息
    let os = std::env::consts::OS;
    let arch = std::env::consts::ARCH;

    let goos = match os {
        "macos" => "darwin",
        "windows" => "windows",
        "linux" => "linux",
        other => other,
    };

    let goarch = match arch {
        "x86_64" => "amd64",
        "x86" => "386",
        "aarch64" => "arm64",
        other => other,
    };

    let url = format!(
        "https://gitee.com/dev-linhu/frp/releases/download/v0.64.0/frp_0.64.0_{}_{}.tar.gz",
        goos, goarch
    );

    println!("Download frp from {}", url);

    let client = Client::new();
    let resp = match client.get(&url).send().await {
        Ok(r) => r,
        Err(e) => return ApiResponse::fail(&format!("下载失败: {}", e), None),
    };

    let bytes = match resp.bytes().await {
        Ok(b) => b,
        Err(e) => return ApiResponse::fail(&format!("获取响应内容失败: {}", e), None),
    };

    // 目标解压路径
    let mut extract_path = config_dir().unwrap_or_else(|| PathBuf::from("."));
    extract_path.push("frp-tauri");

    // 如果已经存在整个目录，先删除
    if extract_path.exists() {
        if let Err(e) = fs::remove_dir_all(&extract_path) {
            return ApiResponse::fail(&format!("清理旧目录失败: {}", e), None);
        }
    }

    if let Err(e) = fs::create_dir_all(&extract_path) {
        return ApiResponse::fail(&format!("创建目录失败: {}", e), None);
    }

    // 解压 tar.gz
    let gz = GzDecoder::new(&bytes[..]);
    let mut archive = Archive::new(gz);
    if let Err(e) = archive.unpack(&extract_path) {
        return ApiResponse::fail(&format!("解压失败: {}", e), None);
    }

    // 拼接到 frpc 可执行文件路径
    let frpc_path = extract_path
        .join(format!("frp_0.64.0_{}_{}", goos, goarch))
        .join("frpc");

    // 设置可执行权限 (mac/linux)
    #[cfg(unix)]
    {
        use std::os::unix::fs::PermissionsExt;
        if let Err(e) = fs::set_permissions(&frpc_path, fs::Permissions::from_mode(0o755)) {
            return ApiResponse::fail(&format!("设置执行权限失败: {}", e), None);
        }
    }

    ApiResponse::ok(
        "frpc tar.gz 解压成功",
        Some(frpc_path.to_string_lossy().to_string()),
    )
}


/// frpc.toml 默认路径
pub fn frpc_toml_path() -> PathBuf {
    let mut path = config_dir().unwrap_or_else(|| PathBuf::from("."));
    path.push("frp-tauri");
    fs::create_dir_all(&path).ok();
    path.push("frpc.toml");
    
    path
}

/// 根据当前 client.config 生成 frpc.toml
pub fn frpc_toml() -> ApiResponse<()> {
    // 获取 client.config
    let result = crate::controller::setting::get_setting("client.config");
    if result.code == 0 {
        return ApiResponse::fail(&format!("获取 client.config 失败: {}", result.msg), None);
    }

    let config = match result.data {
        Some(v) => v,
        None => return ApiResponse::fail("client.config 为空", None),
    };

    // 基础信息
    let mut toml = format!(
        "serverAddr = \"{}\"\nserverPort = {}\n\nwebServer.addr = \"{}\"\nwebServer.port = {}\nwebServer.user = \"{}\"\nwebServer.password = \"{}\"\n\n",
        config.get("server_addr").and_then(|v| v.as_str()).unwrap_or_default(),
        config.get("server_port").and_then(|v| v.as_i64()).unwrap_or(0),
        config.get("client_addr").and_then(|v| v.as_str()).unwrap_or_default(),
        config.get("client_port").and_then(|v| v.as_i64()).unwrap_or(0),
        config.get("client_user").and_then(|v| v.as_str()).unwrap_or_default(),
        config.get("client_password").and_then(|v| v.as_str()).unwrap_or_default(),
    );

    // 遍历 proxies
    if let Some(proxies) = config.get("proxies").and_then(|v| v.as_array()) {
        for proxy in proxies {
            let status = proxy.get("status")
                .and_then(|v| v.as_i64())
                .unwrap_or(0);
            if status != 1 {
                continue;
            }


            let proxy_type = proxy.get("proxy_type").and_then(|v| v.as_str()).unwrap_or("tcp");

            let domains = proxy.get("custom_domains")
                .and_then(|v| v.as_array())
                .map(|arr| arr.iter().filter_map(|v| v.as_str()).collect::<Vec<_>>().join("\", \""))
                .unwrap_or_default();

            toml.push_str(&format!(
                "[[proxies]]\nname = \"{}\"\ntype = \"{}\"\nlocalIP = \"{}\"\nlocalPort = {}",
                proxy.get("name").and_then(|v| v.as_str()).unwrap_or_default(),
                proxy_type,
                proxy.get("local_ip").and_then(|v| v.as_str()).unwrap_or_default(),
                proxy.get("local_port").and_then(|v| v.as_i64()).unwrap_or(0)
            ));

            // 根据 proxy_type 添加特有字段
            match proxy_type {
                "tcp" | "udp" => {
                    let remote_port = proxy.get("remote_port").and_then(|v| v.as_i64()).unwrap_or(0);
                    toml.push_str(&format!("\nremotePort = {}", remote_port));
                },
                "http" | "https" => {
                    if !domains.is_empty() {
                        toml.push_str(&format!("\ncustomDomains = [\"{}\"]", domains));
                    }
                },
                "tcpmux" => {
                    // tcpmux 特有字段
                    // if let Some(mux) = proxy.get("multiplexer").and_then(|v| v.as_str()) {
                    //     toml.push_str(&format!("\nmultiplexer = \"{}\"", mux));
                    // }

                    toml.push_str(&format!("\nmultiplexer = \"{}\"", "httpconnect"));
                    if !domains.is_empty() {
                        toml.push_str(&format!("\ncustomDomains = [\"{}\"]", domains));
                    }
                    if let Some(route) = proxy.get("routeByHTTPUser").and_then(|v| v.as_str()) {
                        toml.push_str(&format!("\nrouteByHTTPUser = \"{}\"", route));
                    }
                },
                _ => {}
            }

            toml.push_str("\n\n");
        }
    } else {
        println!("----- Warning: proxies not found in config -----");
    }


    let path = frpc_toml_path();
    match fs::write(&path, toml) {
        Ok(_) => ApiResponse::ok("frpc toml reset success", None),
        Err(e) => ApiResponse::fail(&format!("写入 frpc.toml 失败: {}", e), None),
    }
}

lazy_static! {
    static ref FRPC_PROCESS: Mutex<Option<Child>> = Mutex::new(None);
}

/// 启动 frpc
#[command]
pub async fn frpc_start() -> ApiResponse<()> {
    let result = crate::controller::setting::get_setting("client.config");

    // 检查获取结果
    if result.code == 0 {
        return ApiResponse::fail("获取配置失败！", None);
    }

    // 反序列化数据
    let data = match result.data {
        Some(v) => v,
        None => return ApiResponse::fail("配置数据为空", None),
    };

    let config: crate::controller::setting::ClientConfig = match serde_json::from_value(data) {
        Ok(c) => c,
        Err(e) => return ApiResponse::fail(format!("解析 client.config 失败: {}", e), None),
    };

    let child_result = if config.client_server_type == 1 {
        // 使用 go run 启动
        let go_cmd = &config.client_go;
        let project_dir = &config.client_project;
        let toml_path = &config.client_frpc_toml;

        if go_cmd.is_empty() || project_dir.is_empty() || toml_path.is_empty() {
            return ApiResponse::fail("client_go, client_project 或 client_frpc_toml 未配置", None);
        }

        Command::new(go_cmd)
            .arg("run")
            .arg(".")
            .arg("-c")
            .arg(toml_path)
            .current_dir(project_dir)
            .spawn()
    } else if config.client_server_type == 2 {
        // 使用可执行文件启动
        let frpc_path = &config.client_server_path;
        let toml_path = &config.client_frpc_toml;

        if frpc_path.is_empty() || toml_path.is_empty() {
            return ApiResponse::fail("client_server_path 或 client_frpc_toml 未配置", None);
        }
        Command::new(frpc_path)
            .arg("-c")
            .arg(toml_path)
            .spawn()
    } else {
        return ApiResponse::fail("未知启动方式", None);
    };

    let child = match child_result {
        Ok(c) => c,
        Err(e) => return ApiResponse::fail(format!("启动 frpc 失败: {}", e), None),
    };

    let mut frpc = FRPC_PROCESS.lock().unwrap();
    *frpc = Some(child);

    crate::controller::setting::set_setting("client.start.status", json!(1));
    crate::controller::setting::set_setting(
        "client.start.update_time",
        Value::String(crate::utils::time::get_current_time()),
    );

    ApiResponse::ok("frpc 已启动", None)
}

#[command]
pub async fn frpc_reload() -> ApiResponse<()> {

    // 每次生成最新 frpc.toml
    let result = frpc_toml();
    if result.code == 0 {
        return ApiResponse::fail(result.msg, None);
    }

    let result = crate::controller::setting::get_setting("client.config");

    if result.code == 0 {
        return ApiResponse::fail("获取配置失败！", None);
    }

    let client_config = match result.data {
        Some(v) => v,
        None => return ApiResponse::fail("client 配置为空！", None),
    };

    let client_addr = client_config.get("client_addr")
        .and_then(|v| v.as_str())
        .unwrap_or("127.0.0.1");
    let client_port = client_config.get("client_port")
        .and_then(|v| v.as_i64())
        .unwrap_or(8000);

    let base_url = format!("http://{}:{}/api", client_addr, client_port);
    let http_client = Client::new();

     // 读取 frpc.toml 原文
    let toml_path = frpc_toml_path();
    let toml_content = match fs::read_to_string(&toml_path) {
        Ok(content) => content,
        Err(e) => return ApiResponse::fail(&format!("读取 frpc.toml 失败: {}", e), None),
    };

    // 1. PUT /config
    let put_res = http_client
        .put(format!("{}/config", base_url))
        .body(toml_content) // 把本地 client 配置作为 JSON 发送
        .send()
        .await;


    match put_res {
        Ok(resp) => {

        }
        Err(e) => return ApiResponse::fail(&format!("请求 PUT /config 失败: {}", e), None),
    }

    // 2. POST /frpc_reload
    let reload_res = http_client
        .get(format!("{}/reload", base_url))
        .send()
        .await;

    println!("PUT /reload: {:?}", format!("{}/reload", base_url));
    
    match reload_res {
        Ok(resp) => {
            ApiResponse::ok("frpc 重载成功", None)
        }
        Err(e) => ApiResponse::fail(&format!("请求 POST /frpc_reload 失败: {}", e), None),
    }
}

/// 停止 frpc
#[command]
pub async fn frpc_stop() -> ApiResponse<()> {
    let result = crate::controller::setting::get_setting("client.config");
    if result.code == 0 {
        return ApiResponse::fail(format!("获取配置失败: {}", result.msg), None);
    }

    let data = result.data.unwrap();
    let client_port = data.get("client_port")
        .and_then(|v| v.as_u64())
        .unwrap_or(8000) as u16;

    // 获取所有 TCP 套接字
    let sockets_info = match get_sockets_info(
        AddressFamilyFlags::IPV4 | AddressFamilyFlags::IPV6,
        ProtocolFlags::TCP,
    ) {
        Ok(s) => s,
        Err(e) => return ApiResponse::fail(format!("获取端口失败: {}", e), None),
    };

    // 遍历查找监听 client_port 的进程
    for si in sockets_info {
        if let ProtocolSocketInfo::Tcp(tcp_si) = si.protocol_socket_info {
            if tcp_si.local_port == client_port {
                if let Some(pid) = si.associated_pids.first() {
                    #[cfg(unix)]
                    {
                        unsafe {
                            libc::kill(*pid as i32, libc::SIGKILL);
                        }
                    }

                    #[cfg(windows)]
                    {
                        use std::process::Command;
                        let _ = Command::new("taskkill")
                            .args(["/PID", &pid.to_string(), "/F"])
                            .status();
                    }

                    return ApiResponse::ok(format!("端口 {} 对应的进程已杀掉", client_port), None);
                }
            }
        }
    }

    ApiResponse::fail(format!("未找到占用端口 {} 的进程", client_port), None)
}


/// 启动或重启 frpc
#[command]
pub async fn frpc_run() -> ApiResponse<()> {

    // 每次生成最新 frpc.toml
    let result = frpc_toml();
    if result.code == 0 {
        return ApiResponse::fail(result.msg, None);
    }

    let result = crate::controller::setting::get_setting("client.config");
    if result.code == 0 {
        return ApiResponse::fail(format!("获取 配置失败: {}", result.msg), None);
    }

    // 取 data
    let data = result.data.unwrap(); // serde_json::Value
    // 提取 client_addr 和 client_port
    let client_addr = data.get("client_addr")
        .and_then(|v| v.as_str())
        .unwrap_or("127.0.0.1"); // 默认值

    let client_port = data.get("client_port")
        .and_then(|v| v.as_u64())
        .unwrap_or(8000) as u16; // 默认值并转换成 u16

    // 调用异步检测函数
    let server_status = crate::utils::sys::check_server(client_addr, client_port).await;
    if server_status == 0 {
        return frpc_start().await;
    } else {
        return frpc_reload().await;
    }

}

#[command]
pub async fn frpc_check() -> ApiResponse<()> {
    let result = frpc_toml();
    if result.code == 0 {
        return ApiResponse::fail(result.msg, None);
    }

    let result = crate::controller::setting::get_setting("client.config");
    if result.code == 0 {
        return ApiResponse::fail(format!("获取 配置失败: {}", result.msg), None);
    }

    let data = result.data.unwrap();
    let client_addr = data.get("client_addr").and_then(|v| v.as_str()).unwrap_or("127.0.0.1"); 

    let client_port = data.get("client_port").and_then(|v| v.as_u64()).unwrap_or(8000) as u16;

    let r =  crate::utils::sys::check_server(client_addr, client_port).await;
    if r == 0 {
        return ApiResponse::fail("frpc 未启动", None);
    }

    return ApiResponse::ok("已启动", None);
}